"""
设备资产管理服务
提供设备资产的CRUD操作和业务逻辑
"""

import logging
import json
from typing import List, Optional, Dict, Any
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_, func

from src.app.database.models import Asset
from src.app.database.database import get_database_manager
from src.app.modules.asset.cache import AssetCache
from src.app.modules.asset.utils import AssetUtils

logger = logging.getLogger(__name__)

class AssetService:
    """设备资产管理服务类"""
    
    def __init__(self):
        self.db_manager = get_database_manager()
        self.cache = AssetCache()
        self.utils = AssetUtils()
    
    def create_asset(self, asset_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        创建设备资产
        
        Args:
            asset_data: 设备资产数据
            
        Returns:
            创建结果
        """
        # 验证数据
        is_valid, error_msg = self.utils.validate_asset_data(asset_data)
        if not is_valid:
            return {'success': False, 'message': error_msg}
        
        # 检查资产编码是否重复
        with self.db_manager.get_session() as session:
            existing_asset = session.query(Asset).filter(
                Asset.asset_code == asset_data['asset_code']
            ).first()
            
            if existing_asset:
                return {'success': False, 'message': f"资产编码 {asset_data['asset_code']} 已存在"}
        
        try:
            # 生成资产ID
            asset_id = self.utils.generate_asset_id()
            
            # 处理设备组成关系
            device_composition = asset_data.get('device_composition', [])
            if isinstance(device_composition, list):
                asset_data['device_composition'] = self.utils.format_device_composition(device_composition)
            
            # 创建资产记录
            asset = Asset(
                asset_id=asset_id,
                asset_type=asset_data['asset_type'],
                asset_name=asset_data['asset_name'],
                asset_code=asset_data['asset_code'],
                model=asset_data.get('model'),
                device_composition=asset_data.get('device_composition'),
                cpu_cores=asset_data.get('cpu_cores'),
                memory_gb=asset_data.get('memory_gb'),
                storage_capacity=asset_data.get('storage_capacity'),
                hard_disk_count=asset_data.get('hard_disk_count'),
                hard_disk_specs=asset_data.get('hard_disk_specs'),
                department=asset_data.get('department'),
                purpose_desc=asset_data.get('purpose_desc')
            )
            
            with self.db_manager.get_session() as session:
                session.add(asset)
                session.commit()
                session.refresh(asset)
            
            # 清除相关缓存
            self.cache.clear_cache()
            
            logger.info(f"成功创建设备资产: {asset_id}")
            return {
                'success': True, 
                'message': '设备资产创建成功',
                'data': {'asset_id': asset_id}
            }
            
        except Exception as e:
            logger.error(f"创建设备资产失败: {e}")
            return {'success': False, 'message': f"创建失败: {str(e)}"}
    
    def update_asset(self, asset_id: str, asset_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        更新设备资产
        
        Args:
            asset_id: 设备资产ID
            asset_data: 更新数据
            
        Returns:
            更新结果
        """
        # 验证更新数据（使用专门的更新验证方法）
        is_valid, error_msg = self.utils.validate_update_data(asset_data)
        if not is_valid:
            return {'success': False, 'message': error_msg}
        
        try:
            with self.db_manager.get_session() as session:
                # 查询资产
                asset = session.query(Asset).filter(Asset.asset_id == asset_id).first()
                if not asset:
                    return {'success': False, 'message': '设备资产不存在'}
                
                # 检查资产编码是否重复（排除当前资产）
                if 'asset_code' in asset_data:
                    existing_asset = session.query(Asset).filter(
                        and_(
                            Asset.asset_code == asset_data['asset_code'],
                            Asset.asset_id != asset_id
                        )
                    ).first()
                    
                    if existing_asset:
                        return {'success': False, 'message': f"资产编码 {asset_data['asset_code']} 已存在"}
                
                # 处理设备组成关系
                if 'device_composition' in asset_data:
                    device_composition = asset_data['device_composition']
                    if isinstance(device_composition, list):
                        asset_data['device_composition'] = self.utils.format_device_composition(device_composition)
                
                # 更新字段
                for field, value in asset_data.items():
                    if hasattr(asset, field):
                        setattr(asset, field, value)
                
                session.commit()
                
                # 清除相关缓存
                self.cache.invalidate_asset(asset_id)
                self.cache.clear_cache("asset_statistics")
                
                logger.info(f"成功更新设备资产: {asset_id}")
                return {'success': True, 'message': '设备资产更新成功'}
                
        except Exception as e:
            logger.error(f"更新设备资产失败: {e}")
            return {'success': False, 'message': f"更新失败: {str(e)}"}
    
    def delete_asset(self, asset_id: str) -> Dict[str, Any]:
        """
        删除设备资产
        
        Args:
            asset_id: 设备资产ID
            
        Returns:
            删除结果
        """
        try:
            with self.db_manager.get_session() as session:
                # 查询资产
                asset = session.query(Asset).filter(Asset.asset_id == asset_id).first()
                if not asset:
                    return {'success': False, 'message': '设备资产不存在'}
                
                # 检查关联关系
                if asset.os_systems:
                    return {'success': False, 'message': '该资产关联了操作系统，无法删除'}
                
                if asset.business_systems:
                    return {'success': False, 'message': '该资产关联了业务系统，无法删除'}
                
                if asset.ips:
                    return {'success': False, 'message': '该资产关联了IP地址，无法删除'}
                
                # 删除资产
                session.delete(asset)
                session.commit()
                
                # 清除相关缓存
                self.cache.invalidate_asset(asset_id)
                self.cache.clear_cache()
                
                logger.info(f"成功删除设备资产: {asset_id}")
                return {'success': True, 'message': '设备资产删除成功'}
                
        except Exception as e:
            logger.error(f"删除设备资产失败: {e}")
            return {'success': False, 'message': f"删除失败: {str(e)}"}
    
    def get_asset_by_id(self, asset_id: str) -> Optional[Dict[str, Any]]:
        """
        根据ID获取设备资产
        
        Args:
            asset_id: 设备资产ID
            
        Returns:
            设备资产信息
        """
        def fetch_from_db():
            with self.db_manager.get_session() as session:
                asset = session.query(Asset).filter(Asset.asset_id == asset_id).first()
                if asset:
                    return {
                        'asset_id': asset.asset_id,
                        'asset_type': asset.asset_type,
                        'asset_name': asset.asset_name,
                        'asset_code': asset.asset_code,
                        'model': asset.model,
                        'device_composition': self.utils.parse_device_composition(asset.device_composition),
                        'cpu_cores': asset.cpu_cores,
                        'memory_gb': asset.memory_gb,
                        'storage_capacity': asset.storage_capacity,
                        'hard_disk_count': asset.hard_disk_count,
                        'hard_disk_specs': asset.hard_disk_specs,
                        'department': asset.department,
                        'purpose_desc': asset.purpose_desc,
                        'create_time': asset.create_time.isoformat() if asset.create_time else None,
                        'update_time': asset.update_time.isoformat() if asset.update_time else None
                    }
                return None
        
        return self.cache.get_asset_by_id(asset_id, fetch_from_db)
    
    def get_all_assets(self, filters: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
        """
        获取所有设备资产
        
        Args:
            filters: 筛选条件
            
        Returns:
            设备资产列表
        """
        try:
            with self.db_manager.get_session() as session:
                query = session.query(Asset)
                
                # 应用筛选条件
                if filters:
                    if 'asset_type' in filters and filters['asset_type']:
                        query = query.filter(Asset.asset_type == filters['asset_type'])
                    
                    if 'department' in filters and filters['department']:
                        query = query.filter(Asset.department == filters['department'])
                    
                    if 'asset_name' in filters and filters['asset_name']:
                        name = f"%{filters['asset_name']}%"
                        query = query.filter(Asset.asset_name.like(name))
                
                assets = query.all()
                
                result = []
                for asset in assets:
                    asset_data = {
                        'asset_id': asset.asset_id,
                        'asset_type': asset.asset_type,
                        'asset_name': asset.asset_name,
                        'asset_code': asset.asset_code,
                        'model': asset.model,
                        'device_composition': self.utils.parse_device_composition(asset.device_composition),
                        'cpu_cores': asset.cpu_cores,
                        'memory_gb': asset.memory_gb,
                        'storage_capacity': asset.storage_capacity,
                        'hard_disk_count': asset.hard_disk_count,
                        'hard_disk_specs': asset.hard_disk_specs,
                        'department': asset.department,
                        'purpose_desc': asset.purpose_desc,
                        'create_time': asset.create_time.isoformat() if asset.create_time else None,
                        'update_time': asset.update_time.isoformat() if asset.update_time else None
                    }
                    result.append(asset_data)
                
                # 应用额外的筛选条件
                if filters:
                    result = self.utils.filter_assets(result, filters)
                
                return result
                
        except Exception as e:
            logger.error(f"获取设备资产列表失败: {e}")
            return []
    
    def get_assets_by_type(self, asset_type: str) -> List[Dict[str, Any]]:
        """
        根据类型获取设备资产
        
        Args:
            asset_type: 资产类型
            
        Returns:
            设备资产列表
        """
        def fetch_from_db():
            return self.get_all_assets({'asset_type': asset_type})
        
        return self.cache.get_assets_by_type(asset_type, fetch_from_db)
    
    def get_assets_by_department(self, department: str) -> List[Dict[str, Any]]:
        """
        根据部门获取设备资产
        
        Args:
            department: 部门名称
            
        Returns:
            设备资产列表
        """
        def fetch_from_db():
            return self.get_all_assets({'department': department})
        
        return self.cache.get_assets_by_department(department, fetch_from_db)
    
    def get_asset_statistics(self) -> Dict[str, Any]:
        """
        获取设备资产统计信息
        
        Returns:
            统计信息字典
        """
        def fetch_from_db():
            try:
                with self.db_manager.get_session() as session:
                    # 基础统计
                    total_count = session.query(func.count(Asset.asset_id)).scalar()
                    
                    # 按类型统计
                    type_stats = session.query(
                        Asset.asset_type,
                        func.count(Asset.asset_id).label('count')
                    ).group_by(Asset.asset_type).all()
                    
                    # 按部门统计
                    dept_stats = session.query(
                        Asset.department,
                        func.count(Asset.asset_id).label('count')
                    ).group_by(Asset.department).all()
                    
                    # 硬件资源统计
                    resource_stats = session.query(
                        func.sum(Asset.cpu_cores).label('total_cpu'),
                        func.sum(Asset.memory_gb).label('total_memory'),
                        func.sum(Asset.storage_capacity).label('total_storage')
                    ).first()
                    
                    # 构建统计结果
                    stats = {
                        'total_count': total_count or 0,
                        'by_type': {},
                        'by_department': {},
                        'total_cpu_cores': int(resource_stats.total_cpu or 0),
                        'total_memory_gb': float(resource_stats.total_memory or 0),
                        'total_storage_capacity': float(resource_stats.total_storage or 0)
                    }
                    
                    # 处理类型统计
                    for asset_type, count in type_stats:
                        type_name = self.utils.get_asset_type_display(asset_type)
                        stats['by_type'][type_name] = count
                    
                    # 处理部门统计
                    for department, count in dept_stats:
                        dept_name = department or '未分配'
                        stats['by_department'][dept_name] = count
                    
                    return stats
                    
            except Exception as e:
                logger.error(f"获取设备资产统计信息失败: {e}")
                return {}
        
        return self.cache.get_asset_statistics(fetch_from_db)
    
    def get_asset_types(self) -> List[Dict[str, str]]:
        """
        获取所有资产类型
        
        Returns:
            资产类型列表
        """
        try:
            with self.db_manager.get_session() as session:
                types = session.query(Asset.asset_type).distinct().all()
                
                result = []
                for (asset_type,) in types:
                    result.append({
                        'code': asset_type,
                        'name': self.utils.get_asset_type_display(asset_type)
                    })
                
                return result
                
        except Exception as e:
            logger.error(f"获取资产类型失败: {e}")
            return []
    
    def get_departments(self) -> List[str]:
        """
        获取所有部门
        
        Returns:
            部门列表
        """
        try:
            with self.db_manager.get_session() as session:
                departments = session.query(Asset.department).distinct().all()
                
                result = []
                for (department,) in departments:
                    if department:  # 过滤空值
                        result.append(department)
                
                return sorted(result)
                
        except Exception as e:
            logger.error(f"获取部门列表失败: {e}")
            return []
    
    def export_assets(self, filters: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
        """
        导出设备资产数据
        
        Args:
            filters: 筛选条件
            
        Returns:
            导出数据列表
        """
        assets = self.get_all_assets(filters)
        return self.utils.export_assets_to_dict(assets)
    
    def get_cache_info(self) -> Dict[str, Any]:
        """
        获取缓存信息
        
        Returns:
            缓存信息字典
        """
        return self.cache.get_cache_info()
    
    def clear_cache(self, pattern: Optional[str] = None) -> None:
        """
        清除缓存
        
        Args:
            pattern: 缓存键模式
        """
        self.cache.clear_cache(pattern)